In-class Exercise 3

In this exercise, I learnt how to create an interactive chart in R

Sia Heng Guang https://www.linkedin.com/in/hengguang/ (MITB Analytics Track)https://scis.smu.edu.sg/
2022-01-29

Installaing relevant libraries

packages = c('ggiraph', 'plotly', 'DT', 'patchwork', 
             'gganimate', 'tidyverse', 'readxl', 'gifski',
             'gapminder')

for (p in packages){
  if(!require(p, character.only = T)){
    install.packages(p)
  }
  library(p, character.only = T)
}

Importing data

exam_data <- read_csv("data/Exam_data.csv")

Plotting a normal dot plot using ggplot2

Firstly, plot a normal dot plot using ggplot2 with the Maths results:

ggplot(data=exam_data, 
       aes(x = MATHS)) +
  geom_dotplot(binwidth=2.5, 
               dotsize = 0.5) +
  scale_y_continuous(NULL, 
                     breaks = NULL)

Plotting an interactive chart using ggiraph using ID

Convert to ggiraph interactive dot plot, with aesthetic mapping for the tooltip.

The girafe function passes the plot and converts it into an svg with specified width and height.

p <- ggplot(data=exam_data, 
       aes(x = MATHS)) +
  geom_dotplot_interactive(
    aes(tooltip = ID),
    stackgroups = TRUE, 
    binwidth = 1, 
    method = "histodot") +
  scale_y_continuous(NULL, 
                     breaks = NULL)
girafe(
  ggobj = p,
  width_svg = 6,
  height_svg = 6*0.618
)

Plotting using class aesthetic

p <- ggplot(data=exam_data, 
       aes(x = MATHS)) +
  geom_dotplot_interactive(
    aes(tooltip = CLASS, data_id=CLASS),
    stackgroups = TRUE, 
    binwidth = 1, 
    method = "histodot") +
  scale_y_continuous(NULL, 
                     breaks = NULL)
girafe(
  ggobj = p,
  width_svg = 6,
  height_svg = 6*0.618
)

Showing both CLASS and ID in the tooltip

We first have to create a new column to combine both the Student ID and Class. We do this by using the mutate function.

exam_data <- exam_data %>%
  mutate(CLASSID = paste0(CLASS,", ", ID))

p <- ggplot(data=exam_data, 
       aes(x = MATHS)) +
  geom_dotplot_interactive(
    aes(tooltip = CLASSID, data_id=CLASS),
    stackgroups = TRUE, 
    binwidth = 1, 
    method = "histodot") +
  scale_y_continuous(NULL, 
                     breaks = NULL)
girafe(
  ggobj = p,
  width_svg = 6,
  height_svg = 6*0.618
)

To showcase highlighting effects

p <- ggplot(data=exam_data, 
       aes(x = MATHS)) +
  geom_dotplot_interactive(              
    aes(data_id = CLASS),              
    stackgroups = TRUE,                  
    binwidth = 1,                        
    method = "histodot") +               
  scale_y_continuous(NULL,               
                     breaks = NULL)
girafe(                                  
  ggobj = p,                             
  width_svg = 6,                         
  height_svg = 6*0.618,
  options = list(
    opts_hover(css = "fill: #202020;"),
    opts_hover_inv(css = "opacity:0.2;")
  )
)

To showcase on-click effects

exam_data$onclick <- sprintf("window.open(\"%s%s\")",
"https://www.moe.gov.sg/schoolfinder?journey=Primary%20school", as.character(exam_data$ID) )
p <- ggplot(data=exam_data, 
       aes(x = MATHS)) +
  geom_dotplot_interactive(              
    aes(onclick = onclick),
    stackgroups = TRUE,                  
    binwidth = 1,                        
    method = "histodot") +               
  scale_y_continuous(NULL,               
                     breaks = NULL)
girafe(                                  
  ggobj = p,                             
  width_svg = 6,                         
  height_svg = 6*0.618)

To patch 2 different graphs together

p1 <- ggplot(data=exam_data, 
       aes(x = MATHS)) +
  geom_dotplot_interactive(              
    aes(tooltip = ID, data_id = ID),              
    stackgroups = TRUE,                  
    binwidth = 1,                        
    method = "histodot") +  
  coord_cartesian(xlim=c(0,100)) +
  scale_y_continuous(NULL,               
                     breaks = NULL)

p2 <- ggplot(data=exam_data, 
       aes(x = ENGLISH)) +
  geom_dotplot_interactive(              
    aes(data_id = ID),              
    stackgroups = TRUE,                  
    binwidth = 1,                        
    method = "histodot") + 
  coord_cartesian(xlim=c(0,100)) +
  scale_y_continuous(NULL,               
                     breaks = NULL)
girafe(code = print(p1 / p2),
       width_svg = 6,
       height_svg = 6,
       options = list(
         opts_hover(css = "fill: #202020;"),
         opts_hover_inv(css = "opacity:0.2;")
         )
       )

Using plotly

The following shows how to create an interactive chart using the package plotly.

Plotly for a scatter plot

We first plot a basic scatter plot:

plot_ly(data = exam_data, 
             x = ~ENGLISH, 
             y = ~MATHS)

We can see the interactive elements in the output, with the basic hovering showing the English and Math (E, M) scores.

Plotting with basic filter of RACE

plot_ly(data = exam_data, 
        x = ~ENGLISH, 
        y = ~MATHS, 
        color = ~RACE)

Changing a colour palette

plot_ly(data = exam_data, 
        x = ~ENGLISH, 
        y = ~MATHS, 
        color = ~RACE, 
        colors = "Set1")

Mapping a user-defined colour palette

Define a colour palette using a vector and assigning it to the corresponding number of bins

pal <- c("red", "purple", "blue", "green")

plot_ly(data = exam_data, 
        x = ~ENGLISH, 
        y = ~MATHS, 
        color = ~RACE, 
        colors = pal)

Adding tool tips

Using text to add tool tips on hover.

plot_ly(data = exam_data, 
        x = ~ENGLISH, 
        y = ~MATHS,
        text = ~paste("Student ID:", ID,
                      "<br>Class:", CLASS),
        color = ~RACE, 
        colors = "Set1")

Formatting the chart

Using layout to add a Title and fix a range for the axes.

plot_ly(data = exam_data, 
        x = ~ENGLISH, 
        y = ~MATHS,
        text = ~paste("Student ID:", ID,     
                      "<br>Class:", CLASS),  
        color = ~RACE, 
        colors = "Set1") %>%
  layout(title = 'English Score versus Maths Score ',
         xaxis = list(range = c(0, 100)),
         yaxis = list(range = c(0, 100)))

Using ggplotly to create an interactive scatter plot

We pass the plot through the ggplotly function:

p <- ggplot(data=exam_data, 
            aes(x = MATHS,
                y = ENGLISH)) +
  geom_point(dotsize = 1) +
  coord_cartesian(xlim=c(0,100),
                  ylim=c(0,100))
ggplotly(p)

Combining multiple graphs using ggplotly:

p1 <- ggplot(data=exam_data, 
              aes(x = MATHS,
                  y = ENGLISH)) +
  geom_point(size=1) +
  coord_cartesian(xlim=c(0,100),
                  ylim=c(0,100))
p2 <- ggplot(data=exam_data, 
            aes(x = MATHS,
                y = SCIENCE)) +
  geom_point(size=1) +
  coord_cartesian(xlim=c(0,100),
                  ylim=c(0,100))
subplot(ggplotly(p1),
        ggplotly(p2))

Adding interactions between the 2 plots:

Using the highlight_key function of the plotly package to synchronise between the 2 plots on selection.

d <- highlight_key(exam_data)

p1 <- ggplot(data=d, 
            aes(x = MATHS,
                y = ENGLISH)) +
  geom_point(size=1) +
  coord_cartesian(xlim=c(0,100),
                  ylim=c(0,100))
p2 <- ggplot(data=d, 
            aes(x = MATHS,
                y = SCIENCE)) +
  geom_point(size=1) +
  coord_cartesian(xlim=c(0,100),
                  ylim=c(0,100))
subplot(ggplotly(p1),
        ggplotly(p2))

Adding a data table

We will now add a data table beside the plot using the DT package. We can preview the data table using the following code:

DT::datatable(exam_data)

We can then link it during the crosstalk package. Using the bscols function, we can place the plots side by side.

d <- highlight_key(exam_data)

p <- ggplot(d, 
            aes(ENGLISH, 
                MATHS)) + 
  geom_point(size=1) +
  coord_cartesian(xlim=c(0,100),
                  ylim=c(0,100))
gg <- highlight(ggplotly(p),
                "plotly_selected")
crosstalk::bscols(gg,
                  DT::datatable(d),
                  widths = 5)

Creating a animated bubble plot

Firstly we create a normal bubble plot

globalPop <- read_xls("data/GlobalPopulation.xls")
ggplot(globalPop, aes(x = Old, y = Young, 
                      size = Population, 
                      colour = Country)) +
  geom_point(alpha = 0.7, 
             show.legend = FALSE) +
  scale_colour_manual(values = country_colors) +
  scale_size(range = c(2, 12)) +
  labs(title = 'Year: {frame_time}', 
       x = '% Aged', 
       y = '% Young')

Adding animations over time

Using the transition_time function to animate it over time, with the linear animation over time.

The country_colors is from the gapminder package.

ggplot(globalPop, aes(x = Old, y = Young, 
                      size = Population, 
                      colour = Country)) +
  geom_point(alpha = 0.7, 
             show.legend = FALSE) +
  scale_colour_manual(values = country_colors) +
  scale_size(range = c(2, 12)) +
  labs(title = 'Year: {frame_time}', 
       x = '% Aged', 
       y = '% Young') +
  transition_time(Year) +
  ease_aes('linear')